zhouqijie

一、程序生成模型

注意事项:把一个物体封装成一个类保存时,最好每个顶点只保存一次。然后用一个索引数组保存三角形的顶点索引。

二、外部载入OBJ格式模型

OBJ文件结构:

\# Blender v2.80 (sub 0) OBJ File: '' \# ... o Pyramid v 1.000000 -1.000000 -1.000000 ... vt 0.5000000, 0.250000 ... vn 0.000000 -1.000000 0.000000 ... s off f 2/1/1 3/2/1 4/3/1 ...

注释:

o-物体名(忽略)
v-顶点
vt-纹理坐标
vn-法向量
s-是否平滑(忽略)
f-面

实现1:(不带索引)

class ModelImporter
{
private:
	std::vector<float> vertVals;
	std::vector<float> stVals;
	std::vector<float> normVals;

	std::vector<float> triangleVerts;
	std::vector<float> textureCoords;
	std::vector<float> normals;
public:
	ModelImporter();
	void parseOBJ(const char *filePath);
	int getNumVertices();
	std::vector<float> getVertices();
	std::vector<float> getTextureCoordinates();
	std::vector<float> getNormals();
};
class Mesh
{
protected:
	int numVertices;
	std::vector<glm::vec3> vertices;
	std::vector<glm::vec2> texCoords;
	std::vector<glm::vec3> normalVecs;
public:
	Mesh();
	Mesh(const char *filePath);
	int getNumVertices();
	std::vector<glm::vec3> getVertices();
	std::vector<glm::vec2> getTextureCoords();
	std::vector<glm::vec3> getNormals();
};

//---------------------------实现------------------------
//------------------------------------------------------
ModelImporter::ModelImporter() {}

void ModelImporter::parseOBJ(const char *filePath)
{
	float x, y, z;
	string content;
	ifstream fileStream(filePath, ios::in);
	string line = "";
	while (!fileStream.eof())
	{
		getline(fileStream, line);
		if (line.compare(0, 2, "v ") == 0)
		{
			stringstream ss(line.erase(0, 1));
			ss >> x; ss >> y; ss >> z;
			vertVals.push_back(x);
			vertVals.push_back(y);
			vertVals.push_back(z);
		}
		if (line.compare(0, 2, "vt") == 0)
		{
			stringstream ss(line.erase(0, 2));
			ss >> x; ss >> y;
			stVals.push_back(x);
			stVals.push_back(y);
		}
		if (line.compare(0, 2, "vn") == 0)
		{
			stringstream ss(line.erase(0, 2));
			ss >> x; ss >> y; ss >> z;
			normVals.push_back(x);
			normVals.push_back(y);
			normVals.push_back(z);
		}
		if (line.compare(0, 2, "f ") == 0)
		{
			string oneCorner, v, t, n;
			stringstream ss(line.erase(0, 2));
			for (int i = 0; i < 3; i++)
			{
				getline(ss, oneCorner, ' ');
				stringstream oneCornerSS(oneCorner);
				getline(oneCornerSS, v, '/');
				getline(oneCornerSS, t, '/');
				getline(oneCornerSS, n, '/');

				int vertRef = 0;
				int tcRef = 0;
				int normRef = 0;

				if (v != "") vertRef = (stoi(v) - 1) * 3;
				if (t != "") tcRef = (stoi(t) - 1) * 2;
				if (n != "") normRef = (stoi(n) - 1) * 3;

				triangleVerts.push_back(vertVals[vertRef]);
				triangleVerts.push_back(vertVals[vertRef + 1]);
				triangleVerts.push_back(vertVals[vertRef + 2]);

				textureCoords.push_back(stVals[tcRef]);
				textureCoords.push_back(stVals[tcRef + 1]);

				normals.push_back(normVals[normRef]);
				normals.push_back(normVals[normRef + 1]);
				normals.push_back(normVals[normRef + 2]);
			}
		}
	}
	fileStream.close();
}
int ModelImporter::getNumVertices() { return (triangleVerts.size() / 3); }
std::vector<float> ModelImporter::getVertices() { return triangleVerts; }
std::vector<float> ModelImporter::getTextureCoordinates() { return textureCoords; }
std::vector<float> ModelImporter::getNormals() { return normals; }
//--------------------------------------------------------------

Mesh::Mesh() {}

Mesh::Mesh(const char *filePath)
{
	ModelImporter modelImporter = ModelImporter();
	modelImporter.parseOBJ(filePath);
	numVertices = modelImporter.getNumVertices();
	std::vector<float> verts = modelImporter.getVertices();
	std::vector<float> tcs = modelImporter.getTextureCoordinates();
	std::vector<float> normals = modelImporter.getNormals();

	for (int i = 0; i < numVertices; i++)
	{
		vertices.push_back(glm::vec3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]));
		texCoords.push_back(glm::vec2(tcs[i * 2], tcs[i * 2 + 1]));
		normalVecs.push_back(glm::vec3(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]));
	}
}

int Mesh::getNumVertices() { return numVertices; }
std::vector<glm::vec3> Mesh::getVertices() { return vertices; }
std::vector<glm::vec2> Mesh::getTextureCoords() { return texCoords; }
std::vector<glm::vec3> Mesh::getNormals() { return normalVecs; }

实现2:(不带索引)

class IndicatedModelImporter
{
private:
	std::vector<float> vertVals;
	std::vector<float> stVals;
	std::vector<float> normVals;

	std::vector<float> triangleVerts;
	std::vector<float> textureCoords;
	std::vector<float> normals;
	
	std::vector<int> inds;
public:
	IndicatedModelImporter();
	void parseOBJ(const char *filePath);
	int getNumVertices();
	std::vector<float> getVertices();
	std::vector<float> getTextureCoordinates();
	std::vector<float> getNormals();
	std::vector<int> getInds();
};

class IndicatedMesh: public Mesh
{
protected:
	//int numVertices;
	//std::vector<glm::vec3> vertices;
	//std::vector<glm::vec2> texCoords;
	//std::vector<glm::vec3> normalVecs;
	std::vector<int> inds;
public:
	IndicatedMesh();
	IndicatedMesh(const char *filePath);
	int getNumVertices();
	std::vector<glm::vec3> getVertices();
	std::vector<glm::vec2> getTextureCoords();
	std::vector<glm::vec3> getNormals();
	std::vector<int> getIndicates();
	int getNumIndicates();
};

//------------------------实现-----------------------------
//--------------------------------------------------------
IndicatedModelImporter::IndicatedModelImporter() { }

void IndicatedModelImporter::parseOBJ(const char *filePath)
{
	float x, y, z;
	string content;
	ifstream fileStream(filePath, ios::in);
	string line = "";
	vector<ivec4> v_t_n;

	while (!fileStream.eof())
	{
		getline(fileStream, line);
		if (line.compare(0, 2, "v ") == 0)
		{
			stringstream ss(line.erase(0, 1));
			ss >> x; ss >> y; ss >> z;
			vertVals.push_back(x);
			vertVals.push_back(y);
			vertVals.push_back(z);
		}
		if (line.compare(0, 2, "vt") == 0)
		{
			stringstream ss(line.erase(0, 2));
			ss >> x; ss >> y;
			stVals.push_back(x);
			stVals.push_back(y);
		}
		if (line.compare(0, 2, "vn") == 0)
		{
			stringstream ss(line.erase(0, 2));
			ss >> x; ss >> y; ss >> z;
			normVals.push_back(x);
			normVals.push_back(y);
			normVals.push_back(z);
		}
		if (line.compare(0, 2, "f ") == 0)
		{
			string oneCorner, v, t, n;
			stringstream ss(line.erase(0, 2));
			for (int i = 0; i < 3; i++)
			{
				getline(ss, oneCorner, ' ');
				stringstream oneCornerSS(oneCorner);
				getline(oneCornerSS, v, '/');
				getline(oneCornerSS, t, '/');
				getline(oneCornerSS, n, '/');

				int vertInd = 0;
				int tcInd = 0;
				int normInd = 0;

				if (v != "") vertInd = stoi(v);
				if (t != "") tcInd = stoi(t);
				if (n != "") normInd = stoi(n);

				//判断
				bool isExist = false;
				int ind = 0;
				for (size_t i = 0; i < v_t_n.size(); i++)
				{
					if (v_t_n[i].x != vertInd)
					{
						break;
					}
					if (v_t_n[i].y != tcInd)
					{
						break;
					}
					if (v_t_n[i].z == normInd)
					{
						isExist = true;
						ind = v_t_n[i].w;
					}
				}
				//根据判断结果
				if (!isExist)
				{
					triangleVerts.push_back(vertVals[(vertInd -1) * 3]);
					triangleVerts.push_back(vertVals[(vertInd - 1) * 3 + 1]);
					triangleVerts.push_back(vertVals[(vertInd - 1) * 3 + 2]);

					textureCoords.push_back(stVals[(tcInd - 1) * 2]);
					textureCoords.push_back(stVals[(tcInd - 1) * 2 + 1]);

					normals.push_back(normVals[(normInd - 1) * 3]);
					normals.push_back(normVals[(normInd - 1) * 3 + 1]);
					normals.push_back(normVals[(normInd - 1) * 3 + 2]);

					int lastIndex = v_t_n.size() - 1;
					v_t_n.push_back(ivec4(vertInd, tcInd, normInd, lastIndex + 1));
					inds.push_back(lastIndex + 1);
				}
				else
				{
					inds.push_back(ind);
				}
			}
		}
	}
	fileStream.close();
}
int IndicatedModelImporter::getNumVertices() { return (triangleVerts.size() / 3); }
std::vector<float> IndicatedModelImporter::getVertices() { return triangleVerts; }
std::vector<float> IndicatedModelImporter::getTextureCoordinates() { return textureCoords; }
std::vector<float> IndicatedModelImporter::getNormals() { return normals; }
std::vector<int> IndicatedModelImporter::getInds() { return inds; }
//--------------------------------------------------------

IndicatedMesh::IndicatedMesh() {}

IndicatedMesh::IndicatedMesh(const char *filePath)
{
	IndicatedModelImporter modelImporter = IndicatedModelImporter();
	modelImporter.parseOBJ(filePath);
	numVertices = modelImporter.getNumVertices();
	std::vector<float> verts = modelImporter.getVertices();
	std::vector<float> tcs = modelImporter.getTextureCoordinates();
	std::vector<float> normals = modelImporter.getNormals();
	
	inds = modelImporter.getInds();

	for (int i = 0; i < numVertices; i++)
	{
		vertices.push_back(glm::vec3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]));
		texCoords.push_back(glm::vec2(tcs[i * 2], tcs[i * 2 + 1]));
		normalVecs.push_back(glm::vec3(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]));
	}
}

int IndicatedMesh::getNumVertices() { return numVertices; }
std::vector<glm::vec3> IndicatedMesh::getVertices() { return vertices; }
std::vector<glm::vec2> IndicatedMesh::getTextureCoords() { return texCoords; }
std::vector<glm::vec3> IndicatedMesh::getNormals() { return normalVecs; }
std::vector<int> IndicatedMesh::getIndicates() { return inds; }
int IndicatedMesh::getNumIndicates() { return inds.size(); }